{
 "metadata": {
  "name": "",
  "signature": "sha256:c41ba98ca104eacba3468a716753a5977634547e66a51d7cb307161ae332cf4f"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Array, struct, and Pyrex\n",
      "======================================================================\n",
      "\n",
      "**NOTE**: this entry was last updated 2007-11-18, and may contain\n",
      "information that is not as relevant today (as of 2013).\n",
      "\n",
      "Overview\n",
      "--------\n",
      "\n",
      "[Pyrex](http://nz.cosc.canterbury.ac.nz/~greg/python/Pyrex/) is a\n",
      "language for writing C extensions to Python. Its syntax is very similar\n",
      "to writing Python. A file is compiled to a file, which is then compiled\n",
      "like a standard C extension module for Python. Many people find writing\n",
      "extension modules with Pyrex preferable to writing them in C or using\n",
      "other tools, such as SWIG.\n",
      "\n",
      "See <http://numeric.scipy.org/> for an explanation of the interface. The\n",
      "following packages support the interface:\n",
      "\n",
      "*\u00a0!NumPy\u00a0(all\u00a0versions)\n",
      "*\u00a0Numeric\u00a0(>=24.2)\n",
      "*\u00a0numarray\u00a0(>=1.5.0)\n",
      "\n",
      "Sharing data malloced by a Pyrex-based extension\n",
      "------------------------------------------------\n",
      "\n",
      "Here is a Pyrex file which shows how to export its data using the array\n",
      "interface. This allows various Python types to have a view of the data\n",
      "without actually copying the data itself."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "cdef extern from \"Python.h\":\n",
      "    ctypedef int Py_intptr_t\n",
      "    void Py_INCREF(object)\n",
      "    void Py_DECREF(object)\n",
      "    object PyCObject_FromVoidPtrAndDesc( void* cobj, void* desc, void (*destr)(void *, void *))\n",
      "    \n",
      "cdef extern from \"stdlib.h\":\n",
      "    ctypedef int size_t\n",
      "    ctypedef long intptr_t\n",
      "    void *malloc(size_t size)\n",
      "    void free(void* ptr)\n",
      "\n",
      "# for PyArrayInterface:\n",
      "CONTIGUOUS=0x01\n",
      "FORTRAN=0x02\n",
      "ALIGNED=0x100\n",
      "NOTSWAPPED=0x200\n",
      "WRITEABLE=0x400\n",
      "\n",
      "ctypedef struct PyArrayInterface:\n",
      "    int version          # contains the integer 2 as a sanity check\n",
      "    int nd               # number of dimensions\n",
      "    char typekind        # kind in array --- character code of typestr\n",
      "    int itemsize         # size of each element\n",
      "    int flags            # flags indicating how the data should be interpreted\n",
      "    Py_intptr_t *shape   # A length-nd array of shape information\n",
      "    Py_intptr_t *strides # A length-nd array of stride information\n",
      "    void *data           # A pointer to the first element of the array\n",
      "\n",
      "cdef void free_array_interface( void* ptr, void *arr ):\n",
      "    cdef PyArrayInterface* inter\n",
      "\n",
      "    inter = <PyArrayInterface*>ptr\n",
      "    arrpy = <object>arr\n",
      "    Py_DECREF( arrpy )\n",
      "    free(inter)\n",
      "\n",
      "ctypedef unsigned char fi\n",
      "ctypedef fi* fiptr\n",
      "cdef class Unsigned8Buf:\n",
      "    cdef fiptr data\n",
      "    cdef Py_intptr_t shape[2]\n",
      "    cdef Py_intptr_t strides[2]\n",
      "    \n",
      "    def __init__(self, int width, int height):\n",
      "        cdef int bufsize\n",
      "        bufsize = width*height*sizeof(fi)\n",
      "        self.data=<fiptr>malloc( bufsize )\n",
      "        if self.data==NULL: raise MemoryError(\"Error allocating memory\")\n",
      "        self.strides[0]=width\n",
      "        self.strides[1]=1 # 1 byte per element\n",
      "        \n",
      "        self.shape[0]=height\n",
      "        self.shape[1]=width\n",
      "    \n",
      "    def __dealloc__(self):\n",
      "            free(self.data)\n",
      "            \n",
      "    property __array_struct__:\n",
      "        def __get__(self):\n",
      "            cdef PyArrayInterface* inter\n",
      "\n",
      "            cdef Py_intptr_t *newshape   # A length-nd array of shape information\n",
      "            cdef Py_intptr_t *newstrides # A length-nd array of stride information\n",
      "            cdef int nd\n",
      "\n",
      "            nd = 2\n",
      "\n",
      "            inter = <PyArrayInterface*>malloc( sizeof( PyArrayInterface ) )\n",
      "            if inter is NULL:\n",
      "                raise MemoryError()\n",
      "\n",
      "            inter.version = 2\n",
      "            inter.nd = nd\n",
      "            inter.typekind = 'u'[0] # unsigned int\n",
      "            inter.itemsize = 1\n",
      "            inter.flags = NOTSWAPPED | ALIGNED | WRITEABLE\n",
      "            inter.strides = self.strides\n",
      "            inter.shape = self.shape\n",
      "            inter.data = self.data\n",
      "            Py_INCREF(self)\n",
      "            obj = PyCObject_FromVoidPtrAndDesc( <void*>inter, <void*>self, free_array_interface)\n",
      "            return obj"
     ],
     "language": "python",
     "metadata": {},
     "outputs": []
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "## Using data malloced elsewhere with a Pyrex-based extension\n",
      "\n",
      "One example is the get_data_copy() function of [_cam_iface_shm.pyx](http://code.astraw.com/projects/motmot/browser/trunk/cam_iface/src/_cam_iface_shm.pyx) in the [motmot camera utilities](http://code.astraw.com/projects/motmot) software. In this use example, an image is copied from shared memory into an externally malloced buffer supporting the {{{__array_struct__}}} interface. (The shared memory stuff has only been tested on linux, but the rest should work anywhere.)\n",
      "\n",
      "## See also\n",
      "\n",
      "* [\"Cookbook/Pyrex_and_NumPy\"]"
     ]
    }
   ],
   "metadata": {}
  }
 ]
}